home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / telecomm / sticpsrc.lzh / SOURCE.ARC / AX_MBX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1990-08-07  |  32.6 KB  |  1,395 lines

  1. /* ax.25 mailbox by w9nk */
  2. /* adapted to CHLNET environment by PE1CHL */
  3. /* outbound forwarding to AX.25 BBS systems added by PE1CHL */
  4.  
  5. #include <stdio.h>
  6. #include <time.h>
  7. #include <ctype.h>
  8. #ifdef    UNIX
  9. #include <sys/types.h>
  10. #endif
  11. #include "global.h"
  12. #include "mbuf.h"
  13. #include "ax25.h"
  14. #include "timer.h"
  15. #include "iface.h"
  16. #include "lapb.h"
  17. #include "smtp.h"
  18. #include "ax_mbx.h"
  19. #include "cmdparse.h"
  20.  
  21. /* #define MBDEBUG */
  22.  
  23. static char mbmenu[]    = "(B)ye, (I)nfo, (S)end >\r";
  24. static char mbprompt[]    = ">\r";
  25. static char mbok[]    = "OK\r";
  26. static char mbno[]    = "NO\r";
  27. static char mberr[]    = "Huh?\r";
  28. static char mbserr[]    = "S command syntax error - format is:\r  S name [@ host] [< from_addr] [$bulletin_id]\r";
  29. static char mbbaduser[] = "Bad user or host name\r";
  30. static char mbsubject[] = "Subject:\r";
  31. static char mbmesg[]    = "Enter message.  Terminate with /EX or ^Z in first column:\r";
  32. static char mbtemp[]    = "Can't create temp file for mail\r";
  33. static char mbqerr[]    = "Couldn't queue message for delivery\r";
  34. static char mbbye[]    = "Goodbye!\r";
  35. static char mbcr[]    = "\r";
  36.  
  37. extern char hostname[];
  38.  
  39. char mbxinfofile[80] = "";
  40. static struct mbx *fwdmbx;        /* currently-connecting mbx */
  41.  
  42. static int mbx_line(),mbx_sid(),mbx_script();
  43. static void mbx_rx(),mbx_tx(),mbx_send(),mbx_doscript();
  44. void mbxfwd();
  45.  
  46. static int dombxconnect();
  47. struct cmds fwdcmds[] = {
  48.     "connect",    dombxconnect,    3,    NULLCHAR,    NULLCHAR,
  49.     NULLCHAR,    NULLFP,        0,    NULLCHAR,    NULLCHAR
  50. };
  51.  
  52. extern char *getnenv();
  53. extern char *strstr();
  54.  
  55. /* find mbx struct for specified axp */
  56.  
  57. static struct mbx *
  58. find_mbx(axp)
  59. register struct ax25_cb *axp;
  60. {
  61.     register struct mbx *m;
  62.  
  63.     for (m = (struct mbx *) ((struct ax25_call *) axp->user)->user;
  64.          m != NULLMBX; m = m->next) {
  65.         if(m->ax25_cb == axp)
  66.             break;
  67.     }
  68.  
  69.     return m;
  70. }
  71.  
  72. /* State-change upcall handler for mailbox */
  73.  
  74. void
  75. mbx_state(axp,old,new,msg)
  76. register struct ax25_cb *axp;
  77. int old,new,msg;
  78.  
  79. {
  80.     register struct mbx *m;
  81.     char *cp;
  82.     struct mbxpath *mbp;
  83.     char mesg[160];
  84.  
  85.     switch (new)
  86.     {
  87.     case CONNECTED:
  88. #ifdef MBDEBUG
  89.         printf("MBX: connected\n");
  90. #endif
  91.         /* check if station already known, and register if not */
  92.         if((m = find_mbx(axp)) == NULLMBX) {
  93.         if((m = (struct mbx *) calloc(1,sizeof(struct mbx))) == NULLMBX) {
  94.             axp->state = DISCONNECTED;    /* send DM */
  95.             return;
  96.         }
  97.  
  98.         /* connect the user to this mbox's user list */
  99.         if((m->next = (struct mbx *) ((struct ax25_call *) axp->user)->user)
  100.              != NULLMBX)
  101.             m->next->prev = m;
  102.  
  103.         ((struct ax25_call *) axp->user)->user = (char *) m;
  104.         m->ax25_cb = axp;
  105.  
  106.         pax25(m->name,&axp->addr.dest);
  107.         cp = index(m->name,'-');
  108.         if (cp != NULLCHAR)        /* get rid of SSID */
  109.             *cp = '\0';
  110.         for (cp = m->name; *cp != '\0'; cp++)
  111.             *cp = tolower(*cp);        /* convert to lowercase */
  112.  
  113.         axp->r_upcall = mbx_rx;
  114.         axp->t_upcall = mbx_tx;
  115. #ifdef MBDEBUG
  116.         printf("MBX: new user %s\n",m->name);
  117. #endif
  118.         log_ax(axp,"Conn to mbox");
  119.  
  120.         sprintf(mesg,"%c[NET-$]\rWelcome to the %s TCP/IP Mailbox\r%s",
  121.                  PID_FIRST|PID_LAST|PID_NO_L3,hostname,mbmenu);
  122.  
  123.         enqueue(&axp->txq,qstring(mesg));
  124.         }
  125.  
  126.         /* send first message when script starts with "s" */
  127.         if (m->state == MBX_CONN)
  128.         mbx_tx(axp,1);
  129.  
  130.         break;
  131.  
  132.     case DISCONNECTED:
  133.         if ((m = find_mbx(axp)) == NULLMBX)
  134.         break;
  135.  
  136.         if(m->prev != NULLMBX)
  137.         m->prev->next = m->next;
  138.         else
  139.         ((struct ax25_call *) axp->user)->user = (char *) m->next;
  140.  
  141.         if(m->next != NULLMBX)
  142.         m->next->prev = m->prev;
  143.  
  144.         if (m->to != NULLCHAR)
  145.         free(m->to);
  146.  
  147.         if (m->tofrom != NULLCHAR)
  148.         free(m->tofrom);
  149.  
  150.         if (m->tomsgid != NULLCHAR)
  151.         free(m->tomsgid);
  152.  
  153.         if (m->fullfrom != NULLCHAR)
  154.         free(m->fullfrom);
  155.  
  156.         if (m->subject != NULLCHAR)
  157.         free(m->subject);
  158.  
  159.         while (m->mbpath != NULLMBXPATH) {
  160.         mbp = m->mbpath->next;
  161.         free(m->mbpath);
  162.         m->mbpath = mbp;
  163.         }
  164.  
  165.         if (m->tfile != NULLFILE)
  166.         fclose(m->tfile);
  167.  
  168.         if (m->script != NULLFILE)
  169.         fclose(m->script);
  170.  
  171.         if (m->smtp_cb != NULLCB)
  172.         if (m->state == MBX_DISC) {    /* expecting DISC? */
  173. #ifdef MBDEBUG
  174.             printf("MBX: mbx_state calls mbxfwd\n");
  175. #endif
  176.             mbxfwd(m->smtp_cb);        /* then, start fwd to next box */
  177.         } else {
  178. #ifdef MBDEBUG
  179.             printf("MBX: mbx_state calls del_session\n");
  180. #endif
  181.             del_session(m->smtp_cb);    /* no, wait a while */
  182.         }
  183.  
  184.         free(m);
  185.         break;
  186.     }
  187. }
  188.  
  189. /* receive upcall for ax.25 */
  190.  
  191. static void mbx_rx(axp,cnt)
  192. struct ax25_cb *axp;
  193. int16 cnt;
  194. {
  195.     struct mbx *m;
  196.     struct mbuf *bp;
  197.     char line[MBXLINE + 1];
  198.     struct mbuf *recvl_ax25();
  199.  
  200.     if((m = find_mbx(axp)) == NULLMBX) {
  201.         disc_ax25(axp);            /* who are you?? */
  202.         return;
  203.     }
  204.  
  205.     while((bp = recvl_ax25(axp,0)) != NULLBUF){ /* get a line of text */
  206.         line[pullup(&bp,line,sizeof(line) - 1)] = '\0';
  207.         rip(line);
  208.         free_p(bp);
  209.         if(mbx_line(m,line) == -1)        /* evaluate inputline */
  210.         break;                /* quit after "bye" */
  211.     }
  212. }
  213.  
  214. /* transmit upcall (used to send a file/mail) */
  215.  
  216. static void
  217. mbx_tx(axp,cnt)
  218. struct ax25_cb *axp;
  219. int16 cnt;
  220. {
  221.     struct mbx *m;
  222.     int remain;
  223.     char *pac;
  224.     char line[MBXLINE + 1];
  225.  
  226.     if((m = find_mbx(axp)) == NULLMBX) {
  227.         disc_ax25(axp);            /* who are you?? */
  228.         return;
  229.     }
  230.  
  231.     switch (m->state)
  232.     {
  233.     case MBX_CONN:                /* connecting? */
  234.     case MBX_SEND:                /* transferring mail? */
  235.         mbx_doscript(m);            /* keep it going */
  236.         break;
  237.  
  238.     case MBX_INFO:                /* sending info? */
  239.     case MBX_BODY:                /* sending mail body? */
  240.         if (m->tfile != NULLFILE) {
  241.         if ((remain = axp->maxframe - len_q(axp->txq)) < 2)
  242.             pac = NULLCHAR;
  243.         else
  244.             if ((pac = malloc(axp->paclen)) != NULLCHAR)
  245.             pac[0] = '\0';        /* clean packet buffer */
  246.  
  247.         while (fgets(line,sizeof(line),m->tfile) != NULLCHAR) {
  248.             rip(line);
  249.             strcat(line,mbcr);
  250.  
  251.             if (pac == NULLCHAR) {
  252.             mbx_msg(m,line);
  253.             remain--;
  254.             } else {
  255.             if ((strlen(pac) + strlen(line)) < axp->paclen){
  256.                 strcat(pac,line);    /* still fits, concat it */
  257.                 continue;        /* read next line */
  258.             }
  259.             if (pac[0] != '\0'){
  260.                 mbx_msg(m,pac);    /* too long, flush old */
  261.                 remain--;
  262.             }
  263.             strcpy(pac,line);
  264.             }
  265.  
  266.             /* when only one packet left in window, stop buffering */
  267.             if (remain < 2 && pac != NULLCHAR){
  268.             if (pac[0] != '\0'){
  269.                 mbx_msg(m,pac);
  270.                 remain--;
  271.             }
  272.             free(pac);
  273.             pac = NULLCHAR;
  274.             }
  275.  
  276.             if (remain <= 0)
  277.             return;            /* window full, pause */
  278.         }
  279.         fclose(m->tfile);
  280.         m->tfile = NULLFILE;
  281.  
  282.         /* don't forget buffered packet */
  283.         if (pac != NULLCHAR){
  284.             if (pac[0] != '\0')
  285.             mbx_msg(m,pac);
  286.             free(pac);
  287.         }
  288.  
  289.         /* got EOF, see what to do next.  when INFO: ->command state */
  290.         /* when BODY: send end-of-message and back to SEND state */
  291.         if (m->state == MBX_INFO) {
  292.             m->state = MBX_CMD;
  293.             mbx_msg(m,(m->sid & MBX_SID) ? mbprompt : mbmenu);
  294.         } else {
  295.             m->state = MBX_SEND;
  296.             if (m->sline[1] == '\0')
  297.             strcpy(m->sline + 1,"\032"); /* default ^Z */
  298.             strcat(m->sline,mbcr);
  299.             mbx_msg(m,m->sline + 1);
  300.             if (mbx_script(m) == 0)
  301.             mbx_doscript(m);
  302.         }
  303.         }
  304.         break;
  305.     }
  306. }
  307.  
  308. /* process one line for the mailbox */
  309.  
  310. static int
  311. mbx_line(m,line)
  312. struct mbx *m;
  313. char *line;
  314. {
  315.     switch (m->state)
  316.     {
  317.     case MBX_CMD:
  318.     switch (tolower(line[0])) {
  319.         case 'b':                /* bye - bye */
  320.         if (!(m->sid & MBX_SID))
  321.            mbx_msg(m,mbbye);
  322.         close_ax25(m->ax25_cb);
  323.         return -1; /* tell line processor to quit */
  324.  
  325.         case 'i': {                /* info */
  326.         if (mbxinfofile[0] == '\0' ||
  327.             (m->tfile = fopen(mbxinfofile,"r")) == NULLFILE)
  328.             mbx_msg(m,(m->sid & MBX_SID) ? mbprompt : mbmenu);
  329.         else {
  330.             m->state = MBX_INFO;
  331.             mbx_tx(m->ax25_cb,1);
  332.         }
  333.         }
  334.         break;
  335.  
  336.         case 's': {
  337.         int badsubj = 0;
  338.  
  339.         /* Get S-command type (B,P,T, etc.) */
  340.  
  341.         if (line[1] == '\0')
  342.             m->stype = ' ';
  343.         else
  344.             m->stype = toupper(line[1]);
  345.  
  346.         if (mbx_to(m,line) == -1) {
  347.             if (m->sid & MBX_SID)
  348.             mbx_msg(m,mbno);
  349.             else {
  350.             mbx_msg(m,mbserr);
  351.             }
  352.             badsubj++;
  353.         }
  354.         else if (validate_address(m->to) == 0) {
  355.             if (m->sid & MBX_SID)
  356.             mbx_msg(m,mbno);
  357.             else
  358.             mbx_msg(m,mbbaduser);
  359.             free(m->to);
  360.             m->to = NULLCHAR;
  361.             if (m->tofrom) {
  362.             free(m->tofrom);
  363.             m->tofrom = NULLCHAR;
  364.             }
  365.             if (m->tomsgid) {
  366.             free(m->tomsgid);
  367.             m->tomsgid = NULLCHAR;
  368.             }
  369.             badsubj++;
  370.         }
  371.  
  372.         if (badsubj)
  373.             mbx_msg(m,(m->sid & MBX_SID) ? mbprompt : mbmenu);
  374.         else {
  375.             m->state = MBX_SUBJ;
  376.             mbx_msg(m,(m->sid & MBX_SID) ? mbok : mbsubject);
  377.         }
  378.         break;
  379.         }
  380.         case '[':                /* SID */
  381.         if (mbx_sid(m,line))        /* check and process it */
  382.             goto huh;            /* error, say huh */
  383.  
  384.         mbx_msg(m,mbprompt);        /* it's okay! */
  385.         break;
  386.  
  387.  
  388.         case 'f':
  389.         if (line[1] == '>' && (m->sid & MBX_SID)) {
  390.             /* RLI BBS' expect us to disconnect if we */
  391.             /* have no mail for them, which of course */
  392.             /* we don't, being rather haughty about our */
  393.             /* protocol superiority. */
  394.             if (m->sid & MBX_SID_RLI) {
  395.             close_ax25(m->ax25_cb);
  396.             return -1;
  397.             } else
  398.             mbx_msg(m,mbprompt);
  399.             break;
  400.         }
  401.         /* Otherwise drop through to "huh?" */
  402.  
  403.         huh:
  404.         default:
  405.         mbx_msg(m,mberr);
  406.         mbx_msg(m,(m->sid & MBX_SID) ? mbprompt : mbmenu);
  407.     }
  408.     break;
  409.  
  410.     case MBX_SUBJ:
  411.     if ((m->subject = malloc(strlen(line) + 1)) == NULLCHAR) {
  412.         close_ax25(m->ax25_cb);
  413.         return -1; /* tell line processor to quit */
  414.     }
  415.  
  416.     strcpy(m->subject,line);
  417.  
  418.     if ((m->sid & MBX_SID) == 0)
  419.         mbx_msg(m,mbmesg);
  420.  
  421.     m->state = MBX_HEAD;
  422.     break;
  423.  
  424.     case MBX_HEAD:
  425.     if (!strncmp(line,"R:",2) && strlen(line) > 14) {
  426.         register struct mbxpath *mbp;
  427.         register char *p;
  428.         char *q;
  429.  
  430.         if ((mbp = (struct mbxpath *) calloc(1,sizeof(struct mbxpath))) == NULLMBXPATH) {
  431.         close_ax25(m->ax25_cb);
  432.         return -1; /* tell line processor to quit */
  433.         }
  434.  
  435.         mbp->next = m->mbpath;
  436.         m->mbpath = mbp;
  437.  
  438.         /* parse the "received date/time" field */
  439.         if (isalpha(line[13]))    /* timezone given? */
  440.         mbp->z = line[13];
  441.  
  442.         line[13] = '\0';
  443.         mbp->mm = atoi(&line[11]);
  444.         line[11] = '\0';
  445.         mbp->hh = atoi(&line[9]);
  446.         mbp->d = atoi(&line[6]);
  447.         line[6] = '\0';
  448.         mbp->m = atoi(&line[4]);
  449.         line[4] = '\0';
  450.         mbp->y = atoi(&line[2]);
  451.  
  452.         /* parse the @bbs field */
  453.         for (p = &line[14]; *p != '\0' && *p != '@'; p++)
  454.         ;
  455.  
  456.         if (*p++ == '@') {
  457.         if (*p == ':')
  458.             p++;
  459.         while (*p == ' ')
  460.             p++;
  461.         q = mbp->name;
  462.         while (isalnum(*p) && (q - mbp->name) < 6) {
  463.             *q++ = tolower(*p);
  464.             p++;
  465.         }
  466.         }
  467.         break;
  468.     }
  469.     m->state = MBX_DATA;            /* no more headers, DATA state */
  470.  
  471.     /* generate full "from" address (return path to sender) */
  472.     {
  473.         char fullfrom[80];
  474.  
  475.         strcpy(fullfrom,(m->tofrom != NULLCHAR)? m->tofrom : m->name);
  476.         if (m->mbpath != NULLMBXPATH && m->mbpath->next != NULLMBXPATH)
  477.         sprintf(fullfrom + strlen(fullfrom),"%%%s",m->mbpath->name);
  478.         sprintf(fullfrom + strlen(fullfrom),"%%%s%s@%s",
  479.         m->name,(m->sid & MBX_SID)? ".bbs":"",hostname);
  480.  
  481.         if ((m->fullfrom = malloc(strlen(fullfrom) + 1)) == NULLCHAR) {
  482.         close_ax25(m->ax25_cb);
  483.         return -1;
  484.         }
  485.  
  486.         strcpy(m->fullfrom,fullfrom);
  487.     }
  488.  
  489.     if (mbx_data(m) == -1) {        /* create temp & write headers */
  490.         mbx_msg(m,mbtemp);
  491.         close_ax25(m->ax25_cb);
  492.         return -1;
  493.     }
  494.     if (line[0] == '\0')            /* skip first line when empty */
  495.         break;
  496.  
  497.     case MBX_DATA:
  498.     if (line[0] == 0x1a ||
  499.         strcmp(line,"/ex") == 0 ||
  500.         strcmp(line,"/EX") == 0)
  501.     {
  502.         char *host;
  503.  
  504.         if ((host = index(m->to,'@')) == NULLCHAR)
  505.         host = hostname;        /* use our hostname */
  506.         else
  507.         host++;                /* use the host part of address */
  508.  
  509.         fseek(m->tfile,0L,0);        /* reset to beginning */
  510.         if (queuejob(NULL,m->tfile,host,m->to,m->fullfrom) != 0)
  511.         mbx_msg(m,mbqerr);
  512.  
  513.         free(m->to);
  514.         m->to = NULLCHAR;
  515.         free(m->fullfrom);
  516.         m->fullfrom = NULLCHAR;
  517.         if (m->tofrom) {
  518.         free(m->tofrom);
  519.         m->tofrom = NULLCHAR;
  520.         }
  521.         if (m->tomsgid) {
  522.         free(m->tomsgid);
  523.         m->tomsgid = NULLCHAR;
  524.         }
  525.         free(m->subject);
  526.         m->subject = NULLCHAR;
  527.         fclose(m->tfile);
  528.         m->tfile = NULLFILE;
  529.         m->state = MBX_CMD;
  530.         mbx_msg(m,(m->sid & MBX_SID) ? mbprompt : mbmenu);
  531.         break;
  532.     }
  533.     /* not done yet! */
  534.     fprintf(m->tfile,"%s\n",line);
  535.     break;
  536.  
  537.     case MBX_CONN:            /* connecting a box */
  538.     mbx_sid(m,line);        /* when a SID received, note it */
  539.                     /* and process incoming data... */
  540.     case MBX_SEND:            /* sending mail */
  541.     case MBX_BODY:            /* transferring mail text */
  542.     switch (m->sline[0])        /* look at current script op */
  543.     {
  544.     case 'r':            /* receiving something */
  545.         if (line[0] == '\0')    /* ignore empty lines */
  546.         break;
  547.  
  548.         if (strstr(line,m->sline + 1) != NULL) {
  549.         if (mbx_script(m) == 0)
  550.             mbx_doscript(m);
  551.         else
  552.             m->state = MBX_DISC;
  553.         } else {
  554.         if (m->state == MBX_CONN) {
  555.             close_ax25(m->ax25_cb);
  556.         } else {
  557.             strcpy(m->smtp_cb->buf,line);
  558.             logerr(m->smtp_cb);
  559.         }
  560.         }
  561.         break;
  562.  
  563.     case 'w':            /* awaiting something */
  564.         if (strstr(line,m->sline + 1) != NULL) {
  565.         if (mbx_script(m) == 0)
  566.             mbx_doscript(m);
  567.         else
  568.             m->state = MBX_DISC;
  569.         }
  570.         break;
  571.     }
  572.     break;
  573.     }
  574.  
  575.     return 0;
  576. }
  577.  
  578. /* process the SID [BOX-VER-CAP] */
  579. static int
  580. mbx_sid(m,line)
  581. struct mbx *m;
  582. char *line;
  583. {
  584.     int len = strlen(line);
  585.  
  586.     if (line[len - 1] == ']') {        /* must be an SID */
  587.     m->sid = MBX_SID;
  588.  
  589.     /* Now check to see if this is an RLI board. */
  590.     /* As usual, Hank does it a bit differently from */
  591.     /* the rest of the world. */
  592.     if (len >= 5 &&            /* [RLI] at a minimum */
  593.         strncmp(&line[1],"RLI",3) == 0) {
  594.         m->sid |= MBX_SID_RLI;
  595.     }
  596.  
  597.     return 0;
  598.     }
  599.  
  600.     return 1;                /* not an SID */
  601. }
  602.  
  603. /* send something to the connected station */
  604. static
  605. mbx_msg(m,msg)
  606. struct mbx *m;
  607. char msg[];
  608. {
  609.     int len;
  610.     struct mbuf *bp;
  611.  
  612.     len = strlen(msg);
  613.  
  614.     if ((bp = alloc_mbuf(len+1)) == NULLBUF) {
  615.     disc_ax25(m->ax25_cb);
  616.     return -1;
  617.     }
  618.  
  619.     bp->cnt = len + 1;
  620.     *bp->data = PID_FIRST | PID_LAST | PID_NO_L3;
  621.     memcpy(bp->data+1,msg,len);
  622.  
  623.     send_ax25(m->ax25_cb,bp);
  624.     return 0;
  625. }
  626.  
  627.  
  628. /* States for send line parser state machine */
  629.  
  630. #define        SKIP_CMD        1
  631. #define        LOOK_FOR_USER   2
  632. #define        IN_USER        3
  633. #define        AFTER_USER        4
  634. #define        LOOK_FOR_HOST   5
  635. #define        IN_HOST        6
  636. #define        AFTER_HOST        7
  637. #define        LOOK_FOR_FROM   8
  638. #define        IN_FROM        9
  639. #define        AFTER_FROM        10
  640. #define        LOOK_FOR_MSGID  11
  641. #define        IN_MSGID        12
  642. #define        FINAL_STATE        13
  643. #define        ERROR_STATE        14
  644.  
  645. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  646.  * return 0
  647.  */
  648. static
  649. mbx_to(m,cp)
  650. struct mbx *m;
  651. register char *cp;
  652. {
  653.     int state;
  654.     char *user,*host,*from,*msgid;
  655.     int userlen = 0,hostlen = 0,fromlen = 0,msgidlen = 0;
  656.  
  657.     for (state = SKIP_CMD; state < FINAL_STATE; cp++) {
  658. #ifdef MBDEBUG
  659.     printf("MBX: State is %d, char is %c\n", state, *cp);
  660. #endif
  661.     switch (state) {
  662.         case SKIP_CMD:
  663.         if (*cp == '\0')
  664.             state = ERROR_STATE;    /* no user */
  665.         else if (isspace(*cp))
  666.             state = LOOK_FOR_USER;
  667.         break;
  668.         case LOOK_FOR_USER:
  669.         if (*cp == '\0' || *cp == '@' || *cp == '<' || *cp == '$')
  670.             state = ERROR_STATE;    /* no user */
  671.         else if (!isspace(*cp)) {    /* found start of user */
  672.             user = cp;            /* point at start */
  673.             userlen++;            /* start counting */
  674.             state = IN_USER;
  675.         }
  676.         break;
  677.         case IN_USER:
  678.         switch (*cp) {
  679.             case '\0':            /* found username only */
  680.             state = FINAL_STATE;
  681.             break;
  682.             case '@':
  683.             state = LOOK_FOR_HOST;    /* hostname should follow */
  684.             break;
  685.             case '<':
  686.             state = LOOK_FOR_FROM;    /* from name should follow */
  687.             break;
  688.             case '$':
  689.             state = LOOK_FOR_MSGID; /* message id should follow */
  690.             break;
  691.             default:
  692.             if (isspace(*cp))
  693.                 state = AFTER_USER; /* white space */
  694.             else
  695.                 userlen++;        /* part of username */
  696.         }
  697.         break;
  698.         case AFTER_USER:
  699.         switch (*cp) {
  700.             case '\0':
  701.             state = FINAL_STATE;    /* found username only */
  702.             break;
  703.             case '@':
  704.             state = LOOK_FOR_HOST;    /* hostname follows */
  705.             break;
  706.             case '<':
  707.             state = LOOK_FOR_FROM;    /* fromname follows */
  708.             break;
  709.             case '$':
  710.             state = LOOK_FOR_MSGID; /* message id follows */
  711.             break;
  712.             default:
  713.             if (!isspace(*cp))
  714.                 state = ERROR_STATE;
  715.         }
  716.         break;
  717.         case LOOK_FOR_HOST:
  718.         switch (*cp) {
  719.             case '\0':            /* user@? */
  720.             case '@':            /* user@@ */
  721.             case '<':            /* user@< */
  722.             case '$':            /* user@$ */
  723.             state = ERROR_STATE;
  724.             break;
  725.             default:
  726.             if (!isspace(*cp)) {
  727.                 host = cp;
  728.                 hostlen++;
  729.                 state = IN_HOST;
  730.             }
  731.         }
  732.         break;
  733.         case IN_HOST:
  734.         switch (*cp) {
  735.             case '\0':
  736.             state = FINAL_STATE;    /* found user@host */
  737.             break;
  738.             case '@':
  739.             state = ERROR_STATE;    /* user@host@? */
  740.             break;
  741.             case '<':
  742.             state = LOOK_FOR_FROM;    /* fromname follows */
  743.             break;
  744.             case '$':
  745.             state = LOOK_FOR_MSGID; /* message id follows */
  746.             break;
  747.             default:
  748.             if (isspace(*cp))
  749.                 state = AFTER_HOST;
  750.             else
  751.                 hostlen++;
  752.         }
  753.         break;
  754.         case AFTER_HOST:
  755.         switch (*cp) {
  756.             case '\0':
  757.             state = FINAL_STATE;    /* user@host */
  758.             break;
  759.             case '@':
  760.             state = ERROR_STATE;    /* user@host @ */
  761.             break;
  762.             case '<':
  763.             state = LOOK_FOR_FROM;    /* user@host < */
  764.             break;
  765.             case '$':
  766.             state = LOOK_FOR_MSGID; /* user@host $ */
  767.             break;
  768.             default:
  769.             if (!isspace(*cp))
  770.                 state = ERROR_STATE;/* user@host foo */
  771.         }
  772.         break;
  773.         case LOOK_FOR_FROM:
  774.         switch (*cp) {
  775.             case '\0':            /* user@host <? */
  776.             case '@':            /* user@host <@ */
  777.             case '<':            /* user@host << */
  778.             case '$':            /* user@host <$ */
  779.             state = ERROR_STATE;
  780.             break;
  781.             default:
  782.             if (!isspace(*cp)) {
  783.                 from = cp;
  784.                 fromlen++;
  785.                 state = IN_FROM;
  786.             }
  787.         }
  788.         break;
  789.         case IN_FROM:
  790.         switch (*cp) {
  791.             case '\0':
  792.             state = FINAL_STATE;    /* user@host <foo */
  793.             break;
  794.             case '<':
  795.             state = ERROR_STATE;    /* user@host <foo< */
  796.             break;
  797.             case '$':
  798.             state = LOOK_FOR_MSGID; /* message id follows */
  799.             break;
  800.             default:
  801.             if (isspace(*cp))
  802.                 state = AFTER_FROM;
  803.             else
  804.                 fromlen++;
  805.         }
  806.         break;
  807.         case AFTER_FROM:
  808.         switch (*cp) {
  809.             case '\0':
  810.             state = FINAL_STATE;    /* user@host <foo */
  811.             break;
  812.             case '@':            /* user@host <foo @ */
  813.             case '<':            /* user@host <foo < */
  814.             state = ERROR_STATE;
  815.             break;
  816.             case '$':
  817.             state = LOOK_FOR_MSGID; /* user@host <foo $ */
  818.             break;
  819.             default:
  820.             if (!isspace(*cp))
  821.                 state = ERROR_STATE;/* user@host foo */
  822.         }
  823.         break;
  824.         case LOOK_FOR_MSGID:
  825.         if (*cp == '\0')
  826.             state = ERROR_STATE;    /* msgid = $? */
  827.         else if (isspace(*cp))
  828.             state = ERROR_STATE;    /* user@host <foo $ bar */
  829.         else {
  830.             msgid = cp;
  831.             msgidlen++;
  832.             state = IN_MSGID;
  833.         }
  834.         break;
  835.         case IN_MSGID:
  836.         if (*cp == '\0')
  837.             state = FINAL_STATE;
  838.         else if (isspace(*cp))
  839.             state = FINAL_STATE;
  840.         else
  841.             msgidlen++;
  842.         break;
  843.         default:
  844.         /* what are we doing in this state? */
  845.         state = ERROR_STATE;
  846.     }
  847.     }
  848.  
  849.     if (state == ERROR_STATE)
  850.     return -1;     /* syntax error */
  851.  
  852.     if ((m->to = malloc(userlen + hostlen + 2)) == NULLCHAR)
  853.     return -1;     /* no room for to address */
  854.  
  855.     strncpy(m->to,user,userlen);
  856.     m->to[userlen] = '\0';
  857.  
  858.     if (hostlen) {
  859.     m->to[userlen] = '@';
  860.     strncpy(m->to + userlen + 1,host,hostlen);
  861.     m->to[userlen + hostlen + 1] = '\0';
  862.     }
  863.  
  864.     for (cp = m->to; *cp != '\0'; cp++)
  865.     *cp = tolower(*cp);
  866.  
  867.     if (fromlen) {
  868.     if ((m->tofrom = malloc(fromlen + 1)) == NULLCHAR) {
  869.         free(m->to);
  870.         m->to = NULLCHAR;
  871.         return -1;
  872.     }
  873.     strncpy(m->tofrom,from,fromlen);
  874.     m->tofrom[fromlen] = '\0';
  875.  
  876.     for (cp = m->tofrom; *cp != '\0'; cp++)
  877.         *cp = tolower(*cp);
  878.     }
  879.  
  880.     if (msgidlen) {
  881.     if ((m->tomsgid = malloc(msgidlen + 1)) == NULLCHAR) {
  882.         free(m->to);
  883.         m->to = NULLCHAR;
  884.         if (fromlen) {
  885.         free(m->tofrom);
  886.         m->tofrom = NULLCHAR;
  887.         }
  888.         return -1;
  889.     }
  890.     strncpy(m->tomsgid,msgid,msgidlen);
  891.     m->tomsgid[msgidlen] = '\0';
  892.     }
  893.  
  894.     return 0;
  895. }
  896.  
  897. /* This opens the data file and writes the mail header into it.
  898.  * Returns 0 if OK, and -1 if not.
  899.  */
  900.  
  901. static
  902. mbx_data(m)
  903. struct mbx *m;
  904. {
  905.     time_t t;
  906.     long m_id;
  907.     int i;
  908.     struct mbxpath *mbp;
  909.     char *ptime(),*pxtime();
  910.     extern FILE *tmpfile();
  911.     extern long get_msgid();
  912.  
  913.     if ((m->tfile = tmpfile()) == NULLFILE)
  914.     return -1;
  915.  
  916.     time(&t);
  917.     fprintf(m->tfile,"Received: from %s%s by %s with %s\n\tid AA%ld ; %s",
  918.              m->name,(m->sid & MBX_SID)? ".bbs":"",
  919.              hostname,(m->sid & MBX_SID)? "BBSFWD":"AX25",
  920.              m_id = get_msgid(),ptime(&t));
  921.     fprintf(m->tfile,"Date: %s",m->mbpath == NULLMBXPATH?
  922.              ptime(&t) :
  923.              pxtime(m->mbpath->y,m->mbpath->m,m->mbpath->d,
  924.                 m->mbpath->hh,m->mbpath->mm,m->mbpath->z));
  925.     if (m->tomsgid != NULLCHAR)
  926.     fprintf(m->tfile,"Message-Id: <%s@%s>\n",m->tomsgid,hostname);
  927.     else
  928.     fprintf(m->tfile,"Message-Id: <%ld@%s>\n",m_id,hostname);
  929.     fprintf(m->tfile,"From: %s\n",m->fullfrom);
  930.     fprintf(m->tfile,"To: %s\n",m->to);
  931.     fprintf(m->tfile,"Subject: %s\n",m->subject);
  932.     if (m->stype != ' ')
  933.     fprintf(m->tfile,"X-BBS-Msg-Type: %c\n",m->stype);
  934.     if (m->mbpath != NULLMBXPATH) {
  935.     if (m->mbpath->next == NULLMBXPATH) {
  936.         free(m->mbpath);
  937.         m->mbpath = NULLMBXPATH;
  938.     } else {
  939.         fprintf(m->tfile,"X-BBS-Path: ");
  940.         i = 0;
  941.         while (m->mbpath != NULLMBXPATH) {
  942.         fprintf(m->tfile,"%s",m->mbpath->name);
  943.         mbp = m->mbpath->next;
  944.         free(m->mbpath);
  945.         m->mbpath = mbp;
  946.         if (m->mbpath != NULLMBXPATH) {
  947.             if (++i > 8) {
  948.             fprintf(m->tfile,"\n\t\t");
  949.             i = 0;
  950.             } else {
  951.             fprintf(m->tfile,"!");
  952.             }
  953.         }
  954.         }
  955.         fprintf(m->tfile,"\n");
  956.     }
  957.     }
  958.     fprintf(m->tfile,"\n");            /* blank line before message body */
  959.  
  960.     return 0;
  961. }
  962.  
  963. /* forward jobs to specified AX.25 mailboxes */
  964. void
  965. mbxfwd(cb)
  966. struct smtp_cb *cb;
  967. {
  968.     FILE *script;
  969.     char tmp[MBXLINE];
  970.  
  971.     if (cb->jobq != NULLJOB) do
  972.     {
  973. #ifdef MBDEBUG
  974.         printf("MBX: AX.25 forward to %s\n",cb->jobq->system);
  975. #endif
  976.         sprintf(tmp,"%s%s",getnenv(MAILQDIR),cb->jobq->system);
  977.         if ((script = fopen(tmp,"r")) == NULL)
  978.         continue;
  979.  
  980.         /* read the initial connection line (skip comments) */
  981.         do
  982.         {
  983.         if (fgets(tmp,MBXLINE,script) == NULL)
  984.             tmp[0] = '\0';
  985.  
  986.         rip(tmp);
  987.         } while (tmp[0] == '#');
  988.  
  989. #ifdef MBDEBUG
  990.         printf("MBX: attempt %s\n",tmp);
  991. #endif
  992.  
  993.         if (cmdparse(fwdcmds,tmp)) {    /* attempt a connect */
  994. #ifdef MBDEBUG
  995.         printf("MBX: connect failed\n");
  996. #endif
  997.         fclose(script);
  998.         continue;            /* it failed, try next */
  999.         }
  1000.  
  1001.         fwdmbx->smtp_cb = cb;        /* set values in mbx struct */
  1002.         fwdmbx->script = script;
  1003.  
  1004.         if (mbx_script(fwdmbx) != 0)    /* read next script line */
  1005.         continue;
  1006.  
  1007.         fwdmbx = NULLMBX;            /* prevent mis-use */
  1008.         return;                /* wait for connection */
  1009.     }
  1010.     while (nextjob(cb));            /* some error, try next job */
  1011.  
  1012. #ifdef MBDEBUG
  1013.     printf("MBX: mbxfwd calls del_session\n");
  1014. #endif
  1015.     del_session(cb);            /* all jobs failed */
  1016. }
  1017.  
  1018. /* read next connection/mailing script line */
  1019. static int
  1020. mbx_script (m)
  1021. register struct mbx *m;
  1022.  
  1023. {
  1024.     do
  1025.     {
  1026.     if (fgets(m->sline,MBXLINE,m->script) == NULL) {
  1027. #ifdef MBDEBUG
  1028.         printf("MBX script: EOF\n");
  1029. #endif
  1030.         m->sline[0] = '\0';
  1031.         if (m->state != MBX_DISC)
  1032.         close_ax25(m->ax25_cb); /* terminate connection */
  1033.         m->state = MBX_DISC;    /* we expect a disconnect */
  1034.         return 1;
  1035.     }
  1036.     rip(m->sline);
  1037.     } while (m->sline[0] == '\0' || m->sline[0] == '#');
  1038.  
  1039. #ifdef MBDEBUG
  1040.     printf("MBX script: %s\n",m->sline);
  1041. #endif
  1042.     return 0;
  1043. }
  1044.  
  1045. /* interpret current script line and send output */
  1046.  
  1047. static void
  1048. mbx_doscript (m)
  1049. register struct mbx *m;
  1050.  
  1051. {
  1052.     char *p;
  1053.     struct list *lp;
  1054.     int d;
  1055.     static char type[] = "P";
  1056.     char line[80],tmp[80];
  1057.  
  1058. #ifdef MBDEBUG
  1059.     printf("MBX do_script: %s\n",m->sline);
  1060. #endif
  1061.  
  1062.     switch (m->sline[0])        /* first char is opcode */
  1063.     {
  1064.     case 'b':                /* send mail body */
  1065.     m->state = MBX_BODY;
  1066.     mbx_tx(m->ax25_cb,1);        /* kick off */
  1067.     break;
  1068.  
  1069.     case 'l':                /* loopback point for mail */
  1070.     m->state = MBX_SEND;
  1071.     m->mpos = ftell(m->script);
  1072.     mbx_script(m);
  1073.     mbx_send(m);            /* send the message */
  1074.     break;
  1075.  
  1076.     case 'm':                /* send a mail message */
  1077.     /* make sure we have a message-id.  use job-id when not avail. */
  1078.     if (m->tomsgid == NULLCHAR) {
  1079.         sprintf(tmp,"%s_%s",m->smtp_cb->jobq->jobname,hostname);
  1080.         if ((m->tomsgid = malloc(strlen(tmp) + 1)) != NULLCHAR)
  1081.         strcpy(m->tomsgid,tmp);
  1082.     }
  1083.     /* filter some characters likely to be magic */
  1084.     for (p = m->tomsgid; *p != '\0'; p++)
  1085.         if (index("\"$'();<=>?@[]`{}",*p) != NULLCHAR)
  1086.         *p = '_';
  1087.  
  1088.     /* make sure we have a "from:" address */
  1089.     if (m->tofrom == NULLCHAR) {
  1090.         if ((m->tofrom = malloc(strlen(m->smtp_cb->jobq->from) + 1)) != NULLCHAR)
  1091.         strcpy(m->tofrom,m->smtp_cb->jobq->from);
  1092.     }
  1093.  
  1094.     /* scan "from:", probably of form "rob@pe1chl" or "pe1chl@pe1chl" */
  1095.     /* we want to extract a callsign from this, which is not easy! */
  1096.     /* first, examine the part before the @ sign */
  1097.     d = 0;
  1098.     for (p = m->tofrom; *p != '\0'; p++) {
  1099.         if (!isalnum(*p))
  1100.         break;
  1101.         if (isdigit(*p))        /* count digits */
  1102.         d++;
  1103.     }
  1104.     /* when we got a digit we probably have a callsign */
  1105.     /* when not, look further but watch out for things like: */
  1106.     /* "rob@sys2.pe1chl".  in this case, skip the first part */
  1107.     while (d == 0) {
  1108.         if (p[0] == '\0' || p[1] == '\0') /* more coming? */
  1109.         break;            /* no, use what we have now */
  1110.  
  1111.         strcpy(m->tofrom,p + 1);    /* shift left */
  1112.  
  1113.         for (p = m->tofrom; *p != '\0'; p++) {
  1114.         if (!isalnum(*p)) {    /* next separator */
  1115.             if (!isdigit(p[-1])) /* hack! trap "sys2.pe1chl"-like */
  1116.             d++;        /* break from outer loop */
  1117.             break;
  1118.         }
  1119.         }
  1120.     }
  1121.     *p = '\0';            /* terminate what we have */
  1122.  
  1123.     /* process the destination address.  we want call and bbs in */
  1124.     /* separate fields to be able to massage them in the script */
  1125.     strcpy(tmp,m->smtp_cb->jobq->to->val);
  1126.     if ((p = rindex(tmp,'@')) != NULLCHAR)
  1127.         *p = '\0';            /* chop off @xxxxxx.bbs */
  1128.     if ((p = index(tmp,'%')) != NULLCHAR) {
  1129.         *p++ = '\0';
  1130.     } else {
  1131.         strcpy(p = tmp + 40,m->smtp_cb->jobq->system);
  1132.         if ((p = index(p,'.')) != NULLCHAR)
  1133.         *p = '\0';
  1134.         p = tmp + 40;
  1135.     }
  1136.  
  1137.     /* make a message type. a string allows more flexibility */
  1138.     type[0] = m->stype;
  1139.  
  1140.     /* now, create the "send" command from script and args */
  1141.     strcat(m->sline,mbcr);
  1142.     sprintf(line,m->sline + 1,type,tmp,p,m->tofrom,m->tomsgid,NULL,NULL);
  1143.     mbx_msg(m,line);
  1144.     mbx_script(m);
  1145.     break;
  1146.  
  1147.     case 'n':                /* next mail */
  1148.     log_ax(m->ax25_cb,"MBX sent job %s To: %s From: %s",
  1149.            m->smtp_cb->jobq->jobname,
  1150.            m->smtp_cb->jobq->to->val,
  1151.            m->smtp_cb->jobq->from);
  1152.  
  1153.     /* drop this recepient and check if more */
  1154.     lp = m->smtp_cb->jobq->to->next;
  1155.     free(m->smtp_cb->jobq->to);
  1156.     if ((m->smtp_cb->jobq->to = lp) != NULLLIST && m->mpos != 0) {
  1157.         fseek(m->script,m->mpos,0); /* back to loopback point */
  1158.         mbx_script(m);
  1159.         mbx_send(m);
  1160.         break;
  1161.     }
  1162.  
  1163.     if (m->smtp_cb->errlog != NULLLIST)
  1164.         retmail(m->smtp_cb);    /* return mail when error */
  1165.  
  1166.     unlink(m->smtp_cb->tname);    /* unlink textfile */
  1167.     unlink(m->smtp_cb->wname);    /* unlink workfile */
  1168.  
  1169.     /* check if next job happens to be addressed to same system */
  1170.     strcpy(tmp,m->smtp_cb->jobq->system);
  1171.     if (nextjob(m->smtp_cb) && !strcmp(tmp,m->smtp_cb->jobq->system) && m->mpos != 0) {
  1172.         fseek(m->script,m->mpos,0); /* back to loopback point */
  1173.         mbx_script(m);
  1174.         mbx_send(m);
  1175.         break;
  1176.     }
  1177.  
  1178.     mbx_script(m);            /* no, continue script */
  1179.     mbx_doscript(m);        /* (it will log-off the box) */
  1180.     break;
  1181.  
  1182.     case 's':                /* send a string */
  1183.     strcat(m->sline,mbcr);
  1184.     mbx_msg(m,m->sline + 1);
  1185.     mbx_script(m);
  1186.     break;
  1187.  
  1188.     case 'u':                /* send subject */
  1189.     strcat(m->sline,mbcr);
  1190.     sprintf(line,m->sline + 1,m->subject != NULLCHAR? m->subject : "",NULL,NULL);
  1191.     mbx_msg(m,line);
  1192.     mbx_script(m);
  1193.     break;
  1194.     }
  1195. }
  1196.  
  1197. /* send a message to the (already connected) ax.25 mailbox */
  1198. static void
  1199. mbx_send (m)
  1200. register struct mbx *m;
  1201. {
  1202.     register char *p;
  1203.     struct list *lp;
  1204.     int n = 'A' - 1;
  1205.     char line[MBXLINE];
  1206.     char *getname();
  1207.  
  1208.     if (m->subject != NULLCHAR)
  1209.         free(m->subject);
  1210.     m->subject = NULLCHAR;
  1211.  
  1212.     if (m->tofrom != NULLCHAR)
  1213.         free(m->tofrom);
  1214.     m->tofrom = NULLCHAR;
  1215.  
  1216.     if (m->tomsgid != NULLCHAR)
  1217.         free(m->tomsgid);
  1218.     m->tomsgid = NULLCHAR;
  1219.     m->stype = 'P';
  1220.  
  1221.     /* open message and read headers to get some reqd info */
  1222.  
  1223.     if ((m->tfile = fopen(m->smtp_cb->tname,"r")) == NULLFILE) {
  1224.         close_ax25(m->ax25_cb);        /* too many files? */
  1225.         return;                /* try again later */
  1226.     }
  1227.  
  1228.     while (fgets(line,MBXLINE,m->tfile) != NULL) {
  1229.         rip(line);
  1230.         if (line[0] == '\0')        /* empty line ends headers */
  1231.         break;
  1232.  
  1233.         if (!strncasecmp(line,"subject:",8)) {
  1234.         if (m->subject != NULLCHAR)
  1235.             free(m->subject);
  1236.  
  1237.         for (p = line + 8; *p == ' '; p++)
  1238.             ;
  1239.  
  1240.         if ((m->subject = malloc(strlen(p) + 1)) != NULLCHAR)
  1241.             strcpy(m->subject,p);
  1242.  
  1243. #ifdef MBDEBUG
  1244.         printf("MBX: subject %s\n",m->subject);
  1245. #endif
  1246.         continue;
  1247.         }
  1248.  
  1249.         if (!strncasecmp(line,"from:",5)) {
  1250.         if (m->tofrom != NULLCHAR)
  1251.             free(m->tofrom);
  1252.  
  1253.         for (p = line + 5; *p == ' '; p++)
  1254.             ;
  1255.  
  1256.         if ((m->tofrom = malloc(strlen(p) + 1)) != NULLCHAR)
  1257.             strcpy(m->tofrom,p);
  1258.  
  1259. #ifdef MBDEBUG
  1260.         printf("MBX: from %s\n",m->tofrom);
  1261. #endif
  1262.         continue;
  1263.         }
  1264.  
  1265.         if (!strncasecmp(line,"message-id:",11)) {
  1266.         if (m->tomsgid != NULLCHAR) {
  1267.             free(m->tomsgid);
  1268.             m->tomsgid = NULLCHAR;
  1269.         }
  1270.  
  1271.         if ((p = getname(line)) != NULLCHAR) {
  1272.             if ((m->tomsgid = malloc(strlen(p) + 2)) != NULLCHAR) {
  1273.             /* when multiple recepients, generate unique msgid */
  1274.             if ((lp = m->smtp_cb->jobq->to->next) != NULLLIST) {
  1275.                 while (lp != NULLLIST) {
  1276.                 n++;
  1277.                 lp = lp->next;
  1278.                 }
  1279.  
  1280.                 m->tomsgid[0] = n;        /* A B C... */
  1281.                 m->tomsgid[1] = '\0';
  1282.             } else
  1283.                 m->tomsgid[0] = '\0';
  1284.  
  1285.             strcat(m->tomsgid,p);        /* plus org id */
  1286.             }
  1287.  
  1288. #ifdef MBDEBUG
  1289.             printf("MBX: message-id %s\n",m->tomsgid);
  1290. #endif
  1291.         }
  1292.  
  1293.         continue;
  1294.         }
  1295.  
  1296.         if (!strncasecmp(line,"x-bbs-msg-type:",15)) {
  1297.         for (p = line + 15; *p == ' '; p++)
  1298.             ;
  1299.  
  1300.         m->stype = *p;
  1301.  
  1302. #ifdef MBDEBUG
  1303.         printf("MBX: message type %c\n",m->stype);
  1304. #endif
  1305.         continue;
  1306.         }
  1307.     }
  1308.  
  1309.     fseek(m->tfile,0L,0);        /* rewind to beginning */
  1310.     mbx_doscript(m);        /* start the message xfer */
  1311. }
  1312.  
  1313. static int
  1314. dombxconnect (argc,argv)
  1315. int argc;
  1316. char *argv[];
  1317. {
  1318.     struct ax25 addr;
  1319.     struct ax25_cb *open_ax25();
  1320.     register struct ax25_call *axc;
  1321.     register struct mbx *m;
  1322.     struct interface *ifp;
  1323.     extern int16 axwindow;
  1324.     int i;
  1325.     struct ax25_cb *find_ax25();
  1326.  
  1327.     if((ifp = if_lookup(argv[1])) == NULLIF)
  1328.         return 1;
  1329.  
  1330.     if(!(ifp->flags & IF_AX25))
  1331.         return 1;
  1332.  
  1333.     memset(&addr,0,sizeof(addr));
  1334.     if(setcall(&addr.dest,argv[2]) < 0)
  1335.         return 1;
  1336.  
  1337.     /* Find the MBX call on this interface */
  1338.     for (axc = ax25_port; axc != NULLAXCALL; axc = axc->p_next){
  1339.         if(axc->port == MBOXPORT &&
  1340.            ((axc->flags & MULTI_IF) || axc->interface == ifp)){
  1341.             ASSIGN(addr.source,axc->addr);
  1342.             break;
  1343.         }
  1344.     }
  1345.     if (axc == NULLAXCALL)
  1346.         return 1;
  1347.  
  1348.     /* Check if already connected to that station */
  1349.     if(find_ax25(&addr.dest,&addr.source) != NULLAX25) {
  1350. #ifdef MBDEBUG
  1351.         printf("MBX: already connected!\n");
  1352. #endif
  1353.         return 1;
  1354.     }
  1355.  
  1356.     /* Set digipeater path */
  1357.     if((addr.ndigis = argc - 3) > MAXDIGIS)
  1358.         return 1;
  1359.     for(i=3; i < argc; i++)
  1360.         if(setcall(&addr.digis[i-3],argv[i]) < 0)
  1361.             return 1;
  1362.  
  1363.     if((m = (struct mbx *) calloc(1,sizeof(struct mbx))) == NULLMBX)
  1364.         return 1;
  1365.  
  1366.     /* connect the user to this mbox's user list */
  1367.     if((m->next = (struct mbx *) axc->user) != NULLMBX)
  1368.         m->next->prev = m;
  1369.  
  1370.     axc->user = (char *) m;
  1371.  
  1372.     m->state = MBX_CONN;
  1373.     fwdmbx = m;                /* keep forwarded mbx */
  1374.  
  1375. #ifdef MBDEBUG
  1376.     printf("MBX: calling open_ax25 for %lx\n",m);
  1377. #endif
  1378.     if ((m->ax25_cb = open_ax25(&addr,axwindow,mbx_rx,mbx_tx,mbx_state,
  1379.                        ifp,(char *)axc)) == NULLAX25){
  1380.         if(m->next != NULLMBX)
  1381.         m->next->prev = NULLMBX;
  1382.  
  1383.         axc->user = (char *) m->next;
  1384.         free(m);
  1385.         return 1;
  1386.     }
  1387.  
  1388.     /* set a reasonable value for the idle-link disconnect time */
  1389.     if (m->ax25_cb->t4.start == 0 || TICK2SEC(m->ax25_cb->t4.start) > 1000)
  1390.         m->ax25_cb->t4.start = SEC2TICK(300);
  1391.  
  1392.     return 0;
  1393. }
  1394.  
  1395.